package pers.yefeng.service.impl;

import pers.yefeng.base.View;

import pers.yefeng.constant.StreamConstant;
import pers.yefeng.service.StreamService;
import pers.yefeng.thread.HlsMediaThread;
import pers.yefeng.thread.MediaThread;
import pers.yefeng.utils.BeanCopyUtil;
import pers.yefeng.thread.MediaThreadBuilder;
import pers.yefeng.utils.NetUtil;
import pers.yefeng.utils.StreamUtil;
import pers.yefeng.vo.StreamInfoV0;
import pers.yefeng.vo.StreamParamV0;
import cn.hutool.core.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;

/**
 * @date 2021/05/24 11:29:13
 */
@Slf4j
@Service
public class StreamServiceImpl implements StreamService {


    @Resource(name = "executor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public View<String> start(StreamParamV0 streamParamV0) {
        String sourceAddress = streamParamV0.getSourceAddress();
        if (StringUtils.isBlank(sourceAddress)) {
            return View.error("视频源地址为空！");
        }
        streamParamV0.setSourceAddress(sourceAddress);
        String videoType = streamParamV0.getVideoType();
        if (StringUtils.isBlank(videoType)) {
            videoType = StreamConstant.VIDEO_TYPE_FLV;
        }
        String mapKey = sourceAddress + "-" + videoType;


        // 先检查缓存，如果该摄像头已经开启转流服务，则直接返回地址
        if (ObjectUtil.isNotNull(StreamConstant.MEDIA_INFO_MAP.get(mapKey))) {
            String playAddress = StreamConstant.MEDIA_INFO_MAP.get(mapKey).getPlayAddress();
            if (StreamConstant.VIDEO_TYPE_FLV.equals(videoType)) {
                playAddress = StreamConstant.URL_PLAY_FLV + playAddress;
            } else {
                playAddress = StreamConstant.URL_PLAY_HLS + playAddress + "/" + StreamConstant.VIDEO_FILE_NAME_HLS;
            }
            return View.success("", playAddress);
        }
        // 缓存中不存在，创建新的转流服务

        MediaThread mediaThread = MediaThreadBuilder.create(streamParamV0);
        threadPoolTaskExecutor.execute(mediaThread);

        // 等待服务开启结果
        while (StreamConstant.SERVICE_START_PROGRESS_PROCESSING == mediaThread.getStartProgress()) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        if (StreamConstant.SERVICE_START_PROGRESS_SUCCESS == mediaThread.getStartProgress()) {
            String playAddress = mediaThread.getPlayAddress();
            if (StreamConstant.VIDEO_TYPE_FLV.equals(videoType)) {
                playAddress = StreamConstant.URL_PLAY_FLV + playAddress;
            } else {
                playAddress = StreamConstant.URL_PLAY_HLS + playAddress + "/" + StreamConstant.VIDEO_FILE_NAME_HLS;
            }
            return View.success("", playAddress);
        } else {
            return View.error(mediaThread.getStartProgressMsg());
        }
    }

    @Override
    public View<String> stop(StreamParamV0 streamParamV0) {
        String sourceAddress = streamParamV0.getSourceAddress();
        if (StringUtils.isBlank(sourceAddress)) {
            return View.error("视频源地址为空！");
        }
        streamParamV0.setSourceAddress(sourceAddress);
        String videoType = streamParamV0.getVideoType();
        if (StringUtils.isBlank(videoType)) {
            videoType = StreamConstant.VIDEO_TYPE_FLV;
        }
        String mapKey = sourceAddress + "-" + videoType;
        if (ObjectUtil.isNotNull(StreamConstant.MEDIA_INFO_MAP.get(mapKey))) {
            StreamConstant.MEDIA_INFO_MAP.get(mapKey).stopTransform();
            return View.success();
        }
        return View.success();
    }

    @Override
    public View<List<StreamInfoV0>> listLives() {

        List<StreamInfoV0> streamInfoV0s = BeanCopyUtil.copyListDTO(StreamConstant.MEDIA_INFO_MAP.values(), StreamInfoV0.class);
        return View.success("", streamInfoV0s);
    }

    @Override
    public void getFly(String playAddress, HttpServletRequest request, HttpServletResponse response) {
        // 获取对应线程对象
        MediaThread transferThread = StreamUtil.getPlayAddress(playAddress);
        if (ObjectUtil.isNull(transferThread)) {
            log.error("{}，获取视频流失败！", playAddress);
            return;
        }
        transferThread.addFlvHttpClient(request, response);
    }

    @Override
    public void getHls(String playAddress, String playName, HttpServletRequest request, HttpServletResponse response) {


        // 获取对应线程对象
        MediaThread transferThread = StreamUtil.getPlayAddress(playAddress);
        if (ObjectUtil.isNull(transferThread)) {
            log.error("{}，获取视频流失败！", playAddress);
            return;
        }
        transferThread.getHlsFile(request, response, playName);
    }

    @Override
    public View<Boolean> isOnline(String sourceAddress) {
        if (StringUtils.isBlank(sourceAddress)) {
            return View.error("视频源地址为空！");
        }
        // 获取ip和端口
        String ip;
        int port = 554;
        // 子码流
        if (sourceAddress.contains("sub")) {
            // rtsp://admin:hmsm123456@192.168.22.171:554/h264/ch1/sub/av_stream
            ip = sourceAddress.substring(sourceAddress.indexOf("@") + 1, sourceAddress.lastIndexOf(":"));
            String substring = sourceAddress.substring(sourceAddress.lastIndexOf(":") + 1);
            port = Integer.parseInt(substring.substring(0, substring.indexOf("/")));
        }
        // 主码流
        else {
            // rtsp://admin:12345@192.168.2.65
            ip = sourceAddress.substring(sourceAddress.indexOf("@") + 1);
        }
        return isOnline(ip, port);
    }


    public View<Boolean> isOnline(String ip, Integer port) {
        boolean hostConnectable = NetUtil.isHostConnectable(ip, port);
        return View.success("", hostConnectable);
    }

    @Override
    public void recordHls(HttpServletRequest request, String playAddress, String playName) {

        // 获取对应线程对象
        MediaThread transferThread = StreamUtil.getPlayAddress(playAddress);
        if (ObjectUtil.isNull(transferThread)) {
            return;
        }
        transferThread.recordHls(request, playAddress, playName);
    }

}
